/*
 * Core_Router.cc
 *
 *  Created on: May 20, 2011
 *      Author: ubuntu
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <omnetpp.h>

#include <iostream>
#include <string>

#include "mpls_qos.h"
#include "MPLSPacket.h"

#include "RAR_m.h"
#include "RAA_m.h"
#include "LSP_Cost_Update_m.h"

using namespace std;

typedef struct Routing_Table
{
	int 	LSP_ID;
	double 	Link_Cost;
	char 	Next_Router[10];
	int 	Input_Gate;
	int 	Output_Gate;
	double  Availiable_Bandwidth;
	double  Traffic_Rate;
	double 	Capacity;

}Routing_Table;

class Core_Router : public cSimpleModule
{
	cMessage				 *EndOfSimulation;
	cMessage 				 *Loss_Ratio;
	cOutVector 				  ErrorVector;
	cOutVector 				  FailedVector;
	cOutVector 				  PacketVector;

	double 					  Total_packets, Received;
	double 					  Failed_packets;
	simtime_t 				  timeout;

  protected:
	virtual void 			initialize();
    virtual void 			handleMessage(cMessage *msg);
    virtual RAA             *generateNewRAA_Message(int LSP_ID, int Requested_Bandwidth, bool Reserve  );
    virtual void			UpdateCost(void);
    virtual double 			GetCost(int  index);

    /** This procedure updates the total traffic going through the router every second */
    virtual void 			Update_Rate(void)
    {
    	if ( Received )
    	Total_packets = Received;
    	EV << getName() << ": Total: " << Total_packets << "\n";
    };

  public:
	 Routing_Table Core_Routing_Table[10];

	 Routing_Table & Get_Core_Routing_Table(int index) { return Core_Routing_Table[index]; };
};

Define_Module(Core_Router);

double Core_Router::GetCost(int index)
{
	double Rate 	= Get_Core_Routing_Table(index).Traffic_Rate;
	double Capacity = Get_Core_Routing_Table(index).Capacity;

	if ( Rate < Capacity )
	{
		return 1 / ( 1 - Rate / Capacity );
	}

	else if ( Rate >= Capacity )
	{
		return 100;
	}

	// Just in case
	return 100;
 }

void Core_Router::UpdateCost(void)
{
	if (true)
	{
		if (strcmp("CR4", getName()) == 0)
		{
			Get_Core_Routing_Table(0).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(0).Availiable_Bandwidth = 100 - Total_packets;
		}

		if (strcmp("CR5", getName()) == 0)
		{
			Get_Core_Routing_Table(0).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(0).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(1).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(1).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(2).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(2).Availiable_Bandwidth = 100- Total_packets;
		}
		if (strcmp("CR6", getName()) == 0)
		{
			Get_Core_Routing_Table(0).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(0).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(1).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(1).Availiable_Bandwidth = 100- Total_packets;
		}
		if (strcmp("CR7", getName()) == 0)
		{

			Get_Core_Routing_Table(0).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(0).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(1).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(1).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(2).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(2).Availiable_Bandwidth = 100- Total_packets;
		}
		if (strcmp("CR8", getName()) == 0)
		{
			Get_Core_Routing_Table(0).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(0).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(1).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(1).Availiable_Bandwidth = 100- Total_packets;
		}
		if (strcmp("CR9", getName()) == 0)
		{
			Get_Core_Routing_Table(0).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(0).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(1).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(1).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(2).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(2).Availiable_Bandwidth = 100- Total_packets;
		}
		if (strcmp("CR10", getName()) == 0)
		{
			Get_Core_Routing_Table(0).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(0).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(1).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(1).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(2).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(2).Availiable_Bandwidth = 100- Total_packets;
		}
		if (strcmp("CR11", getName()) == 0)
		{
			Get_Core_Routing_Table(0).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(0).Availiable_Bandwidth = 100- Total_packets;
		}

		if (strcmp("CR12", getName()) == 0)
		{

			Get_Core_Routing_Table(0).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(0).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(1).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(1).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(2).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(2).Availiable_Bandwidth = 100- Total_packets;
		}

		if (strcmp("CR13", getName()) == 0)
		{
			Get_Core_Routing_Table(0).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(0).Availiable_Bandwidth = 100- Total_packets;
			Get_Core_Routing_Table(1).Traffic_Rate      = Total_packets * 1508;
			Get_Core_Routing_Table(1).Availiable_Bandwidth = 100- Total_packets;
		}
	}
}


void Core_Router::initialize()
{
	ErrorVector.setName("Loss_Ratio");
	FailedVector.setName("Failed");
	PacketVector.setName("Packets");

	for(int i = 0; i < 10; i++)
		{
			    Get_Core_Routing_Table(i).LSP_ID = -1;
			    Get_Core_Routing_Table(i).Link_Cost = -1;
			    Get_Core_Routing_Table(i).Input_Gate = -1;
			    Get_Core_Routing_Table(i).Output_Gate = -1;
			    Get_Core_Routing_Table(i).Availiable_Bandwidth = 100;
			    Get_Core_Routing_Table(i).Capacity = 100 * 1508;
			    Get_Core_Routing_Table(i).Traffic_Rate = 0;
		}

	if (strcmp("CR4", getName()) == 0)
	    {
			Get_Core_Routing_Table(0).LSP_ID         = 1;
			Get_Core_Routing_Table(0).Link_Cost      = 0;
			Get_Core_Routing_Table(0).Input_Gate     = 0;
			Get_Core_Routing_Table(0).Output_Gate    = 1;
	    }

	if (strcmp("CR5", getName()) == 0)
	    {
		Get_Core_Routing_Table(0).LSP_ID         = 2;
		Get_Core_Routing_Table(0).Link_Cost      = 0;
		Get_Core_Routing_Table(0).Input_Gate     = 0;
		Get_Core_Routing_Table(0).Output_Gate    = 2;

		Get_Core_Routing_Table(1).LSP_ID         = 3;
		Get_Core_Routing_Table(1).Link_Cost      = 0;
		Get_Core_Routing_Table(1).Input_Gate     = 0;
		Get_Core_Routing_Table(1).Output_Gate    = 3;

		Get_Core_Routing_Table(2).LSP_ID         = 4;
		Get_Core_Routing_Table(2).Link_Cost      = 0;
		Get_Core_Routing_Table(2).Input_Gate     = 1;
		Get_Core_Routing_Table(2).Output_Gate    = 3;
	    }
	if (strcmp("CR6", getName()) == 0)
	{
		Get_Core_Routing_Table(0).LSP_ID         = 5;
		Get_Core_Routing_Table(0).Link_Cost      = 0;
		Get_Core_Routing_Table(0).Input_Gate     = 0;
		Get_Core_Routing_Table(0).Output_Gate    = 2;

		Get_Core_Routing_Table(1).LSP_ID         = 6;
		Get_Core_Routing_Table(1).Link_Cost      = 0;
		Get_Core_Routing_Table(1).Input_Gate     = 0;
		Get_Core_Routing_Table(1).Output_Gate    = 3;
	}
	if (strcmp("CR7", getName()) == 0)
	{
		Get_Core_Routing_Table(0).LSP_ID         = 7;
		Get_Core_Routing_Table(0).Link_Cost      = 0;
		Get_Core_Routing_Table(0).Input_Gate     = 0;
		Get_Core_Routing_Table(0).Output_Gate    = 1;

		Get_Core_Routing_Table(1).LSP_ID         = 8;
		Get_Core_Routing_Table(1).Link_Cost      = 0;
		Get_Core_Routing_Table(1).Input_Gate     = 0;
		Get_Core_Routing_Table(1).Output_Gate    = 1;

		Get_Core_Routing_Table(2).LSP_ID         = 9;
		Get_Core_Routing_Table(2).Link_Cost      = 0;
		Get_Core_Routing_Table(2).Input_Gate     = 0;
		Get_Core_Routing_Table(2).Output_Gate    = 2;

	}
	if (strcmp("CR8", getName()) == 0)
	{

		Get_Core_Routing_Table(0).LSP_ID         = 1;
		Get_Core_Routing_Table(0).Link_Cost      = 0;
		Get_Core_Routing_Table(0).Input_Gate     = 0;
		Get_Core_Routing_Table(0).Output_Gate    = 2;

		Get_Core_Routing_Table(1).LSP_ID         = 2;
		Get_Core_Routing_Table(1).Link_Cost      = 0;
		Get_Core_Routing_Table(1).Input_Gate     = 1;
		Get_Core_Routing_Table(1).Output_Gate    = 2;
	}
	if (strcmp("CR9", getName()) == 0)
	{

		Get_Core_Routing_Table(0).LSP_ID         = 3;
		Get_Core_Routing_Table(0).Link_Cost      = 0;
		Get_Core_Routing_Table(0).Input_Gate     = 0;
		Get_Core_Routing_Table(0).Output_Gate    = 2;

		Get_Core_Routing_Table(1).LSP_ID         = 4;
		Get_Core_Routing_Table(1).Link_Cost      = 0;
		Get_Core_Routing_Table(1).Input_Gate     = 0;
		Get_Core_Routing_Table(1).Output_Gate    = 3;

		Get_Core_Routing_Table(2).LSP_ID         = 5;
		Get_Core_Routing_Table(2).Link_Cost      = 0;
		Get_Core_Routing_Table(2).Input_Gate     = 1;
		Get_Core_Routing_Table(2).Output_Gate    = 3;

	}
	if (strcmp("CR10", getName()) == 0)
	{
		Get_Core_Routing_Table(0).LSP_ID         = 6;
		Get_Core_Routing_Table(0).Link_Cost      = 0;
		Get_Core_Routing_Table(0).Input_Gate     = 0;
		Get_Core_Routing_Table(0).Output_Gate    = 3;

		Get_Core_Routing_Table(1).LSP_ID         = 7;
		Get_Core_Routing_Table(1).Link_Cost      = 0;
		Get_Core_Routing_Table(1).Input_Gate     = 1;
		Get_Core_Routing_Table(1).Output_Gate    = 3;

		Get_Core_Routing_Table(2).LSP_ID         = 8;
		Get_Core_Routing_Table(2).Link_Cost      = 0;
		Get_Core_Routing_Table(2).Input_Gate     = 1;
		Get_Core_Routing_Table(2).Output_Gate    = 2;

	}
	if (strcmp("CR11", getName()) == 0)
	{
		Get_Core_Routing_Table(0).LSP_ID         = 9;
		Get_Core_Routing_Table(0).Link_Cost      = 0;
		Get_Core_Routing_Table(0).Input_Gate     = 0;
		Get_Core_Routing_Table(0).Output_Gate    = 1;
	}
	if (strcmp("CR12", getName()) == 0)
	{

		Get_Core_Routing_Table(0).LSP_ID         = 1;
		Get_Core_Routing_Table(0).Link_Cost      = 0;
		Get_Core_Routing_Table(0).Input_Gate     = 0;
		Get_Core_Routing_Table(0).Output_Gate    = 2;

		Get_Core_Routing_Table(1).LSP_ID         = 2;
		Get_Core_Routing_Table(1).Link_Cost      = 0;
		Get_Core_Routing_Table(1).Input_Gate     = 0;
		Get_Core_Routing_Table(1).Output_Gate    = 2;

		Get_Core_Routing_Table(2).LSP_ID         = 3;
		Get_Core_Routing_Table(2).Link_Cost      = 0;
		Get_Core_Routing_Table(2).Input_Gate     = 1;
		Get_Core_Routing_Table(2).Output_Gate    = 2;

	}

	if (strcmp("CR13", getName()) == 0)
	{
		Get_Core_Routing_Table(0).LSP_ID         = 8;
		Get_Core_Routing_Table(0).Link_Cost      = 0;
		Get_Core_Routing_Table(0).Input_Gate     = 0;
		Get_Core_Routing_Table(0).Output_Gate    = 2;

		Get_Core_Routing_Table(1).LSP_ID         = 9;
		Get_Core_Routing_Table(1).Link_Cost      = 0;
		Get_Core_Routing_Table(1).Input_Gate     = 1;
		Get_Core_Routing_Table(1).Output_Gate    = 2;


	}

	Total_packets = Failed_packets = Received = 0;

	timeout = 1.0;
	Loss_Ratio = new cMessage("Loss_Ratio");
	scheduleAt(simTime()+timeout, Loss_Ratio);

	EndOfSimulation = new cMessage("EndOfSimulation");
	scheduleAt(1.0*5*60, EndOfSimulation);

}

void Core_Router::handleMessage(cMessage *msg)
{
	string RARClass 			("RAR");
	string RAAClass 			("RAA");
	string LSP_Cost_UpdateClass ("LSP_Cost_Update");
	string MPLSClass 			("MPLSPacket");

	if ( msg == Loss_Ratio )
	{
		if (Received)
		{
			if (Failed_packets)
			EV << "Loss Ratio: " << Failed_packets/Total_packets << "\n";

			ErrorVector.record(Received/Total_packets);

			FailedVector.record(Failed_packets);
			PacketVector.record(Total_packets);

		}

		Update_Rate();
		UpdateCost();
		Received = Failed_packets = 0;


		scheduleAt(simTime()+timeout, Loss_Ratio);
	}

	else if (msg == EndOfSimulation)
		{
			 EV << "Simulation Ended\n";
			 cancelAndDelete(EndOfSimulation);
			 cancelAndDelete(Loss_Ratio);
			 return;
		}

	else if ( !LSP_Cost_UpdateClass.compare(msg->getClassName()) )
	{
		LSP_Cost_Update *ttmsg = check_and_cast<LSP_Cost_Update *>(msg);

		for (int i = 0; i < 3; i++)
		{

			if ( Get_Core_Routing_Table(i).LSP_ID == ttmsg->getLSP_ID()  )
			{
				Get_Core_Routing_Table(i).Link_Cost = GetCost(i);

				EV << getName() << ": Cost:" << GetCost(i) << " LSP:" << Get_Core_Routing_Table(i).LSP_ID << "\n";

				if ( (ttmsg->getCost() < GetCost(i)) )
					ttmsg->setCost(GetCost(i));

				send(ttmsg, "gate$o", Get_Core_Routing_Table(i).Input_Gate);

				return;
			}
		}
        delete msg;
	}

	else if ( !RAAClass.compare(msg->getClassName()) )
	{
		RAA *ttmsg = check_and_cast<RAA *>(msg);

		for (int i = 0; i < 3; i++)
		{

			if ( Get_Core_Routing_Table(i).LSP_ID == ttmsg->getLSP_ID()  )
			{
				if ( ttmsg->getReserve() )
				Get_Core_Routing_Table(i).Availiable_Bandwidth -= ttmsg->getRequested_Bandwidth();

				send(ttmsg, "gate$o", Get_Core_Routing_Table(i).Input_Gate);
				return;
			}
		}
        delete msg;
	}

	else if ( !RARClass.compare(msg->getClassName()) )
	{
		RAR *ttmsg = check_and_cast<RAR *>(msg);

		for (int i = 0; i < 3; i++)
		{

			if ( Get_Core_Routing_Table(i).LSP_ID == ttmsg->getLSP_ID() )
			{

				if ( ttmsg->getRequested_Bandwidth() < ( Get_Core_Routing_Table(i).Availiable_Bandwidth - Total_packets ) )
				{
#ifdef DEBUG
					EV << "Forwarding RAR\n";
#endif
					send(ttmsg, "gate$o", Get_Core_Routing_Table(i).Output_Gate);
				}
				else
				{
#ifdef DEBUG
					EV << "Returning RAA\n";
#endif
					delete msg;

					send(generateNewRAA_Message(ttmsg->getLSP_ID(), ttmsg->getRequested_Bandwidth(), false), "gate$o", Get_Core_Routing_Table(i).Input_Gate);
					return;
				}
				return;
			}
		}
        delete msg;
	}

	else if (uniform(0,1) < (double)par("loss_rate"))
	    {
			Failed_packets++;
	        EV << "\"Losing\" message " << msg << endl;
	        bubble("Message lost");
	        delete msg;
	        return;
	    }
	else if ( !MPLSClass.compare(msg->getClassName()) )
	{
		MPLSPacket *ttmsg = check_and_cast<MPLSPacket *>(msg);

#ifdef DEBUG
		EV << "MPLS received at " << getName() << "\n" << "at gate: " <<
				ttmsg->getArrivalGate()->getIndex() << "\n" <<
				"with LSP: " << ttmsg->getTopLabel() << "\n";
#endif

		for (int i = 0; i < 3; i++)
		{

			if ( Get_Core_Routing_Table(i).LSP_ID == ttmsg->getTopLabel() )
			{
#ifdef DEBUG
				EV << "Forwarding MPLS\n";
#endif

					Received++;
					send(ttmsg, "gate$o", Get_Core_Routing_Table(i).Output_Gate);

				return;

			}
		}
        delete msg;
	}
}

RAA *Core_Router::generateNewRAA_Message(int LSP_ID, int Requested_Bandwidth, bool Reserve)
{
	RAA *msg = new RAA();

	msg->setReserve(Reserve);
	msg->setLSP_ID(LSP_ID);
	msg->setRequested_Bandwidth(Requested_Bandwidth);

	return msg;
}
